﻿using System.Diagnostics;

namespace DimensionsHelper.LanguageService.Syntax;

/// <summary>
///     源代码开头的注释指令
/// </summary>
public class Directive : SourceNode
{
    private SourceNode? _fileNode;

    private SourceNode? _nameNode;

    internal Directive(SourceNode file, SourceNode? name) :
        base(SyntaxKinds.Directive)
    {
        SetChildNullableField(ref _nameNode, name);
        SetChildNullableField(ref _fileNode, file);
        DirectiveKind = DirectiveKinds.Reference;
    }


    internal Directive(SourceNode file) :
        base(SyntaxKinds.Directive)
    {
        SetChildNullableField(ref _fileNode, file);
        DirectiveKind = DirectiveKinds.Include;
    }


    internal Directive(DirectiveKinds kind) :
        base(SyntaxKinds.Directive)
    {
        DirectiveKind = kind;
    }


    public DirectiveKinds DirectiveKind { get; private set; }


    public SourceNode? RelativeNameNode => _nameNode;

    public SourceNode? FilePathNode => _fileNode;

    public SourceTextFile? SourceFile { get; internal set; }


    public Directive Update(SourceNode filePathNode)
    {
        SetChildNullableField(ref _fileNode, IsNullOrDefault, filePathNode);
        return this;
    }


    public Directive Update(SourceNode filePathNode, SourceNode relativeNameNode)
    {
        SetChildNullableField(ref _fileNode, IsNullOrDefault, filePathNode);
        SetChildNullableField(ref _nameNode, IsNullOrDefault, relativeNameNode);
        return this;
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        Accept(visitor, RelativeNameNode, FilePathNode);
    }
}


public static partial class NodeFactory
{
    public static Directive CreateDirective(DirectiveKinds kind)
    {
        Debug.Assert(kind != DirectiveKinds.Reference && kind != DirectiveKinds.Include);
        return new Directive(kind);
    }


    public static Directive CreateDirective(SourceNode? file, SourceNode? name)
    {
        Debug.Assert(file != null && file.IsNode(SyntaxKinds.String));
        Debug.Assert(name == null || name.IsNode(SyntaxKinds.String));
        return new Directive(file, name);
    }

    public static Directive CreateDirective(SourceNode? file)
    {
        Debug.Assert(file != null && file.IsNode(SyntaxKinds.String));
        return new Directive(file);
    }
}